
# Copyright 2009 David Lee Miller
#
# This file is part of POSSM (Python Open Source Scanning Microscopy).
#
# POSSM is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# POSSM is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License         
# along with POSSM.  If not, see <http://www.gnu.org/licenses/>.
#                                                                           
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

#from temp_ci import device1
from controller import cPickle,struct,os,time,ws,n

#import cPickle,os,time,struct
#import numpy as n
#import sys
#sys.path.append("/home/stmb/possm/trunk/shared/")
#import worldsettings as ws

import comediExtensions as ce
ce.initDevs(ws.DEV0_NUMBER)

#This file implements the low level functions of the DAC board
#into useful functions for use with the STM. If you wish to use
#a different driver with the software, simply recreate the classes
#and functions in the driver interface. Then create an instance of
#your new class in the socketdaemon and pass them to the classes which
#are defined below.

class SaveDAC(object):
	'''
	Stores the current dac values for all of the
	analog outputs.
	'''
	location = os.environ.get('HOME')
	current_dac = {}
	
	def saveDAC(self,location):
		'''
		Saves the current value of the analog output channel
		to file.
		
		'''
		
		fh = open(location+'/current_values','w')
		cPickle.dump(current_dac,fh)
		fh.close()

savepos = SaveDAC()

class DigitalOutput(object):
	'A class for digital output'
	bits = []
	
	def __init__(self,device,reset=True,saveclass=savepos):
		if device.SUB_DIO == None: raise 'Device does not have DIO capabilities'
		else: self.device = device
		self.saveclass = saveclass
		for i in range(self.device.DIO_BITS):
			self.device.DigitalConfig(i)
		if reset:
			self.clrBit(-1)
		for i in range(self.device.DIO_BITS):
			self.bits.append(0)
	
	def bin(self,a):
		'''
		input 0-255, outputs a string of binary
		'''
		str1=''
		t={'0':'000','1':'001','2':'010','3':'011',
		  '4':'100','5':'101','6':'110','7':'111'}
		for c in oct(a)[1:]: str1+=t[c]
		return str1[-8:] if len(str1)>8 else '0'*(8-len(str1))+str1

	def outp(self,num):
		'''
		Maintains same functionality as outp for the parallel port.
		'''
		str1 = self.bin(num)
		for i in range(8):
			if int(str1[i]): self.setBit(i)
			else: self.clrBit(i)

	def setBit(self,bit):
		'''
		Sets the selected bit to the high value on the digital
		output port. If bit is already set, nothing changes.
		
		Keyword Arguments:
		bit -- the bit (0-7) to set to high
		
		'''
		
		if type(bit) != int and not -1<=bit<=self.device.DIO_BITS-1: raise 'invalid bit!'
		if bit < 0:
			pass
		elif 0 <= bit <= self.device.DIO_BITS-1:
			self.bits[bit] = 1
			self.device.DIOWrite(bit,1)
	
	def clrBit(self,bit):
		'''
		Sets the selected bit to the high value on the digital
		output port. If bit is already set, nothing changes.
		
		Keyword Arguments:
		bit -- the bit (0-7) to set to high
		
		'''
		
		if type(bit) != int and not -1<=bit<=self.device.DIO_BITS-1: raise 'invalid bit!'
		if bit < 0:
			self.bits = []
			for i in range(self.device.DIO_BITS):
				self.device.DIOWrite(i,0)
				self.bits.append(0)
		elif 0 <= bit <= self.device.DIO_BITS-1:
			self.bits[bit] = 1
			self.device.DIOWrite(bit,0)
	
	def setBits(self,bits):
		'''
		Sets the selected bits to the specified values on the digital
		output port. If a bit is already set, nothing changes.
		
		Keyword Arguments:
		bits -- [(bit#,value),(bit#,value),...]
		
		'''
		
		if type(bits) != list: raise 'Invalid type for bits'
		for i in range(len(bits)):
			if 0 <= bits[i][0] <= self.device.DIO_BITS-1:
				self.bits[bits[i][0]] = bits[i][1]
				self.device.DIOWrite(bits[i][0],bits[i][1])
	
	def microdelay(self,ticks):
		'''
		Software timer to delay "ticks" microseconds. Accuracy to less 
		than +-4 microseconds barring system delays.
		
		Keyword Arguments:
		ticks -- Number of 4 microsecond ticks to delay
		
		'''
		smallest_delay = 0.000004
		total_time = 0
		if ticks < 250:
			start_time = time.time()
			while total_time < smallest_delay*ticks:
				total_time = time.time() - start_time
		else:
			mil = ticks/250
			mic = ticks%250
			time.sleep(mil/1000.)
			start_time = time.time()
			while total_time < smallest_delay*mic:
				total_time = time.time() - start_time
	
	def digTrig(self,num,chan):
		'''
		Sends digital triggers.
		
		Keyword arguments:
		num -- the number of triggers to send
		chan -- the integer channel number to output on
		
		First function argument is the number of digital triggers to
		output. Outputs to the channel specified in the second function
		argument.
		
		'''
	
		for i in range(num):
			self.device.DIOWrite(bit,1)
			self.microdelay(3)
			self.device.DIOWrite(bit,0)


class AnalogOutput(object):
	'Talks to a device object and implements its functions'
	
	rng = 0  #the range to use with the device
	
	def __init__(self,device,channel,aoid,reset=True,saveclass=savepos):
		if device.SUB_AO == None: raise 'Device does not have AO capabilities'
		else: self.device = device
		self.channel = channel
		self.saveclass = saveclass
		self.aoid = aoid  #the id name for reference purposes
		if reset:
			self.setVolts(0)
			self.current_dac = device.PhysicalToInteger(device.SUB_AO,channel,self.rng,0)
		#elif saveclass:
			#self.loadDAC(location)
	
	def microdelay(self,ticks):
		'''
		Software timer to delay "ticks" microseconds. Accuracy to less 
		than +-4 microseconds barring system delays.
		
		Keyword Arguments:
		ticks -- Number of 4 microsecond ticks to delay
		
		'''
		smallest_delay = 0.000004
		total_time = 0
		if ticks < 250:
			start_time = time.time()
			while total_time < smallest_delay*ticks:
				total_time = time.time() - start_time
		else:
			mil = ticks/250
			mic = ticks%250
			time.sleep(mil/1000.)
			start_time = time.time()
			while total_time < smallest_delay*mic:
				total_time = time.time() - start_time
	
	def loadDAC(self):
		'''
		Loads the current value of the analog output channel to
		the class.
		
		'''
		
		fh = open(self.saveclass.location+'/current_dac','r')
		params = cPickle.load(fh)
		self.current_dac = current_dac[self.aoid]
		fh.close()
	
	def setDAC(self):
		'''
		Updates the current dac value in the SaveDAC class.
		
		'''
		
		self.saveclass.current_dac[self.aoid] = self.current_dac
	
	def writeSteps(self,nsteps,step,delay=1):
		'''
		Writes nsteps*step from the current location in an integer ramp.
		
		Keyword Arguments:
		nsteps -- number of steps to take
		step -- step size in digital units
		delay -- the delay time in microsleeps
		'''
		if nsteps > 0: direction = 1
		else: direction = -1
		winfo=(self.device.DEV_NO,self.device.SUB_AO,self.channel,self.rng)
		self.current_dac = ce.writeSteps(winfo,self.current_dac,abs(nsteps),direction*step,int(round(delay)))	
		self.setDAC()
		
	
	def writeSingle(self,dac,delay=0,rate=0):
		'''
		Writes a single voltage value to the board.
		
		'''
		
		self.current_dac = self.device.AOInteger(self.channel,self.rng,dac)
		self.setDAC()
		if rate:
			period = (1./rate)*1e6
			self.microdelay(period/4.)
		elif delay: self.microdelay(delay)
		else: pass
	
	def rampVolts(self,end,step,rate=0):
		'''
		Makes the ramp, converts it to integers and ouputs it on
		board.
		
		rate -- the rate in hz to ramp the dac
		'''
		if rate: period = (1./rate)*1e6  #in us
		else: period = 0
		endint = self.device.PhysicalToInteger(self.device.SUB_AO,self.channel,self.rng,end)
		nsteps = abs(endint - self.current_dac)/step
		if endint < self.current_dac: nsteps *= -1
		if not abs(nsteps) < 1: self.writeSteps(nsteps,step,delay=(period/4.))
		#rem = endint - self.current_dac
		#if endint < self.current_dac: rem *= -1
		if endint != self.current_dac: #self.writeSteps(rem,1,delay=(period/4.))
			self.writeSingle(endint)
	
	def setVolts(self,val,rate=0):
		'''
		Steps the voltage to val.
		
		'''
		if rate: period = (1./rate)*1e6  #in us
		else: period = 0
		
		intval = self.device.PhysicalToInteger(self.device.SUB_AO,self.channel,self.rng,val)
		self.writeSingle(intval,delay=(period/4.))
	
	def currentPhysical(self):
		'''
		Returns the value of current_dac in physical units.
		'''
		val = self.device.IntegerToPhysical(self.device.SUB_AO,self.channel,self.rng,self.current_dac)
		return val
	
	def convertToPhysical(self,dac):
		val = self.device.IntegerToPhysical(self.device.SUB_AO,self.channel,self.rng,dac)
		return val
	
	def convertToInteger(self,val):
		'''
		Steps the voltage to val.
		
		'''
		
		intval = self.device.PhysicalToInteger(self.device.SUB_AO,self.channel,self.rng,val)
		return intval



#class AnalogInput(object):
	#'An implementation of the analog input device.'
	
	#rng = 0 #the sampling range to use
	
	#def __init__(self,device,channel):
		#if device.SUB_AI == None: raise 'Device does not have AI capabilities'
		#else: self.device = device
		#self.channel = channel
	
	#def microdelay(self,ticks):
		#'''
		#Software timer to delay "ticks" microseconds. Accuracy to less 
		#than +-4 microseconds barring system delays.
		
		#Keyword Arguments:
		#ticks -- Number of 4 microsecond ticks to delay
		
		#'''
		#smallest_delay = 0.000004
		#total_time = 0
		#if ticks < 250:
			#start_time = time.time()
			#while total_time < smallest_delay*ticks:
				#total_time = time.time() - start_time
		#else:
			#mil = ticks/250
			#mic = ticks%250
			#time.sleep(mil/1000.)
			#start_time = time.time()
			#while total_time < smallest_delay*mic:
				#total_time = time.time() - start_time
	
	##def microdelay(self,useconds):
		##'''
		##Software timer to delay microseconds.
		
		##Keyword Arguments:
		##useconds -- Number of microseconds to delay
		
		##'''
		##ce.microsleep(useconds)
	
	#def readSingle(self):
		#'''
		#Reads a single integer off of the board and converts it to a voltage.
		
		#'''
		
		#intval = self.device.AIInteger(self.channel,self.rng)
		#val = self.device.IntegerToPhysical(self.device.SUB_AI,self.channel,self.rng,intval)
		#return val
	
	#def readFew(self,nscans,ignore=0):
		#'''
		#Takes n samples on a channel, averages them.
		
		#Keyword Arguments:
		#nscans -- the number of points to sample prior to averaging
		
		#'''
		#rinfo=(self.device.DEV_NO,self.device.SUB_AI,self.channel,self.rng)
		#return ce.readFew(rinfo,nscans)
	
	##### Depricated ####
	##def readFew(self,nscans,ignore=0):
		##'''
		##Takes n samples on a channel, averages them.
		
		##Keyword Arguments:
		##nscans -- the number of points to sample prior to averaging
		
		##'''
		
		##datAvg = []
		##for i in range(nscans):
			##dat = [-1,0]
			##while dat[0] < 1:
				##dat = self.device.AIInteger(self.channel,self.rng)
			##datAvg.append(dat[1])
		
		##datAvg = int(n.average(datAvg))
		##datAvg2 = round(self.device.IntegerToPhysical(self.device.SUB_AI,self.channel,self.rng,datAvg),4)
		##return datAvg2
		
	#def convertToPhysical(self,dac):
		#val = self.device.IntegerToPhysical(self.device.SUB_AO,self.channel,self.rng,dac)
		#return val
	
	#def convertToInteger(self,val):
		#'''
		#Steps the voltage to val.
		
		#'''
		
		#intval = self.device.PhysicalToInteger(self.device.SUB_AO,self.channel,self.rng,val)
		#return intval

class ServoFunctions(object):
	'''Low level class for basic device functionality.'''

	TIPVOLTS = 0.0
	ISET = ws.DEFAULT_ISET
	KP = ws.DEFAULT_KP
	KI = ws.DEFAULT_KI
	KD = ws.DEFAULT_KD
	ACTIVE_DAC = 1
	ALPHA = 0.5

	def __init__(self,device):
		#self.device = device // cannot do this
		self.DEV = device.DEV
		ce.initSer(self.DEV.fd)
	
	def TipVolts(self,vlts,rate=500.):
		'''
		Writes a voltage value to the tip.
		
		Keyword Arguments:
		vlts -- a floating point voltage
		
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_V)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',vlts))
		self.TIPVOLTS = vlts
		time.sleep(1./rate)
		return vlts
	
	def CurrentSetpoint(self,vlts):
		'''
		Changes the setpoint for the current.
		
		Keyword Arguments:
		vlts -- a floating point voltage
		
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_I)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',vlts))
		self.ISET = vlts
		return vlts

	def SetPGain(self,kp):
		'''
		Changes the setpoint for the current.
		
		Keyword Arguments:
		vlts -- a floating point voltage
		
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_KP)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',kp))
		self.KP = kp
		return kp

	def SetDGain(self,kd):
		'''
		Changes the setpoint for the current.
		
		Keyword Arguments:
		vlts -- a floating point voltage
		
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_KD)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',kd))
		self.KD = kd
		return kd

	def SetIGain(self,ki):
		'''
		Changes the setpoint for the current.
		
		Keyword Arguments:
		vlts -- a floating point voltage
		
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_KI)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',ki))
		self.KI = ki
		return ki

	def TunnelCurrent(self):
		'''
		Returns the tunneling current from the servo.
		
		'''
		self.DEV.flushInput()
		self.DEV.write(ws.SERIAL_ACQ_I)
		time.sleep(0.001) #account for latency
		res = self.DEV.read(4)
		val = struct.unpack('f',res)
		return val

	def ZHeight1(self):
		'''
		Returns the total height of the tip.
		'''
		self.DEV.flushInput()
		self.DEV.write(ws.SERIAL_ACQ_Z)
		time.sleep(0.001) #account for latency
		res = self.DEV.read(4)
		val = struct.unpack('f',res)
		return val

	def ZHeight(self):
		'''
		Returns the total height of the tip.
		'''
		self.DEV.flushInput()
		self.DEV.flushOutput()
		val = ce.readServo(ws.SERIAL_ACQ_Z)
		return val

	def DACUpdate(self):
		'''
		Gets the voltage extension of the DACS.

		'''
		self.DEV.flushInput()
		self.DEV.flushOutput()
		dachg = ce.readServo(ws.SERIAL_ACQ_HG)
		self.DEV.flushInput()
		self.DEV.flushOutput()
		daclg = ce.readServo(ws.SERIAL_ACQ_LG)
		return (dachg,daclg)

	def GetState(self):
		'''
		Returns the active DAC. 0 = Low gain, 1 = High gain
		'''
		self.DEV.flushInput()
		self.DEV.flushOutput()
		state = ce.readState(ws.SERIAL_ACQ_STATE)
		if (state & (1<<2))==0: self.ACTIVE_DAC = 0
		else: self.ACTIVE_DAC = 1
		return state

	def Retract(self):
		'''
		Puts the retract voltage on the tip and
		stops the servo loop.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_R)
		self.DEV.flushInput()

	def UnRetract(self):
		'''
		Starts the servo loop.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_UR)
		self.DEV.flushInput()

	def Hold(self):
		'''
		Stops the servo loop and leaves the tip
		at the current position.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_H)
		self.DEV.flushInput()

	def UnHold(self):
		'''
		Starts the servo loop.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_UH)
		self.DEV.flushInput()

	def StepResponse(self):
		'''
		Starts the step response calibration mode.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_SR)
		self.DEV.flushInput()
		
	def UnStepResponse(self):
		'''
		Starts the step response calibration mode.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_USR)
		self.DEV.flushInput()

	def SetActiveDAC(self,dac):
		'''
		Sets which DAC does the servoing. 0 or 1
		DAC 0 is the high-gain DAC. If DAC 1 is selected,
		the tip unretracts with DAC0 and swaps the voltage.
		'''
		self.DEV.flushOutput()
		if dac == 0:
			self.DEV.write(ws.SERIAL_SET_LG)
			self.ACTIVE_DAC = 0
		else:
			self.DEV.write(ws.SERIAL_SET_HG)
			self.ACTIVE_DAC = 1
		self.DEV.flushInput()

	def SetupIV(self,npts,vstart,vend,ivtime):
		'''
		Sets the parameters for the IV on the servo.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SETUP_IV)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',npts))
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',vstart))
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',vend))
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',ivtime))

	def IV(self,npts,ivtime):
		'''
		Tells the servo to take an IV and receives the data
		over serial.
		'''
		self.DEV.flushOutput()
		self.DEV.flushInput()
		self.DEV.write(ws.SERIAL_DO_IV)
		#res = ce.readState(ws.SERIAL_DO_IV)
		time.sleep(2.0*ivtime)
		self.DEV.flushOutput()
		self.DEV.flushInput()
		res = ''
		while res != 'D':
			res = self.DEV.read(1)
			if res == 'F': break
			time.sleep(0.001)
		self.DEV.write(ws.SERIAL_GET_IV)
		time.sleep(0.001)
		data = self.DEV.read(4*2*npts) ## retrieve the appropriate number of bits
		data = struct.unpack(2*npts*'f',data) ## unpack into a list
		return list(data)
		

	def ChangeZLG(self,chvlts):
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_CHNG_LG)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',chvlts))
		time.sleep(0.01)

	def SetAlpha(self,alpha):
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_ALPHA)
		time.sleep(0.001)
		self.DEV.write(struct.pack('f',alpha))
		time.sleep(0.01)

	def ResumeTunneling(self):
		'''
		Tells the servo to resume tunneling after a spectroscopy event.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SET_RESUME)
		self.DEV.flushInput()

	def SwapDACVolts(self):
		'''
		Sets which DAC does the servoing. 0 or 1
		DAC 0 is the high-gain DAC. If DAC 1 is selected,
		the tip unretracts with DAC0 and swaps the voltage.
		'''
		self.DEV.flushOutput()
		self.DEV.write(ws.SERIAL_SWAP_V)
		self.DEV.flushInput()


class ServoIO(AnalogOutput, ServoFunctions):
	
	wrng = 0

	def __init__(self,sdevice,wdevice,wchannel,aoid,reset=True,saveclass=savepos):
		assert wdevice.SUB_AO != None  #errors will be printed by AO and AI
		self.device = wdevice
		print self.device.AO_MAXDATA
		self.wdevice = wdevice
		self.sdevice = sdevice
		self.wchannel = wchannel
		AnalogOutput.__init__(self,wdevice,wchannel,aoid,reset=reset,saveclass=saveclass)
		ServoFunctions.__init__(self,sdevice)
	
        def rwScan(self,letter,nsteps,usleep,direction,navgs,step,period=0,rmpstp=0,retw=False):
		'''
		Steps the DAC from position start by the number of steps
		in the given direction and reads a value at each step.
		
		'''
		if rmpstp == 0: rmpstp = step
		winfo=(self.wdevice.DEV_NO,self.wdevice.SUB_AO,self.wchannel,self.wrng)
		## call the externally defined rwScan, letter is the serial request to the servo
		[data,wdata,self.current_dac] = ce.rwScan(letter,winfo,self.current_dac,nsteps,direction,navgs,step,rmpstp,int(round(usleep)),int(round(period)))
		#self.current_dac += direction*nsteps*step*navgs
		if direction == 1:
			if not retw: return data
			else: return data,wdata
		else:
			if not retw: return n.flipud(data)
			else: return n.flipud(data),n.flipud(wdata)

#class AnalogIO(AnalogOutput,AnalogInput):
	
	#wrng = 0
	#rrng = 0
	
	#def __init__(self,rdevice,wdevice,rchannel,wchannel,aoid,reset=True,saveclass=savepos):
		#if rdevice.SUB_AI == None or wdevice.SUB_AO == None: pass  #errors will be printed by AO and AI
		#else:
                    #self.device = wdevice
                    #self.wdevice = wdevice
                    #self.rdevice = rdevice
		#self.wchannel = wchannel
		#self.rchannel = rchannel
		#AnalogOutput.__init__(self,wdevice,wchannel,aoid,reset=reset,saveclass=saveclass)
		#AnalogInput.__init__(self,rdevice,rchannel)
	
        #def rwScan(self,nsteps,usleep,direction,navgs,step,reads,period=0,rmpstp=0,retw=False):
		#'''
		#Steps the DAC from position start by the number of steps
		#in the given direction and reads a value at each step.
		
		#'''
		#if rmpstp == 0: rmpstp = step
		#rinfo=(self.rdevice.DEV_NO,self.rdevice.SUB_AI,self.rchannel,self.rrng)
		#winfo=(self.wdevice.DEV_NO,self.wdevice.SUB_AO,self.wchannel,self.wrng)
		#[data,wdata,self.current_dac] = ce.rwScan(rinfo,winfo,self.current_dac,nsteps,direction,navgs,step,reads,rmpstp,int(round(usleep)),int(round(period)))
		##self.current_dac += direction*nsteps*step*navgs
		#if direction == 1:
			#if not retw: return data
			#else: return data,wdata
		#else:
			#if not retw: return n.flipud(data)
			#else: return n.flipud(data),n.flipud(wdata)
        #### Depricated ####
	#def rwScan(self,nsteps,sleep_wave,direction,navgs,step,reads,period=None):
		#'''
		#Steps the DAC from position start by the number of steps
		#in the given direction and reads a value at each step.
		
		#'''
		##if not start: start = self.current_dac
		#count = 0
		#avg = 0
		#avgcnt = 0
		#avg_lst = []
		#data = []
		##if period != None:
			##period -= ws.READ_TIME
			##if period < 0: period = 0
		##if direction: pts = range(start,start+step*nsteps,step)
		##else: pts = range(start,start-step*nsteps,-step)
		##print self.current_dac,n.array(pts)[::20]
		##print len(sleep_wave)
		#for i in range(nsteps):
			#if i < 0: i = 0
			#elif i > (2**self.device.AO_BITS-1): i = (2**self.device.AO_BITS-1)
			#self.microdelay(sleep_wave.pop())
			#val = self.readFew(reads)
			#if period: self.writeSteps(direction*step,1,delay=(period/4.))
			#else: self.writeSteps(direction*step,1)
			##if i%50==0: print 'dac is:',self.current_dac
			#avg_lst.append(val)
			#if len(avg_lst) == navgs:
				#data.append(avg_lst)
				#avg_lst = []
			#else: pass
		##print 'Current Dac: ',self.current_dac,nsteps
		#data = n.mean(data,1)
		#if direction == 1: return data
		#else: return n.flipud(data)
		
